package com.example.blog.service.impl;

import com.example.blog.dto.SystemLogDTO;
import com.example.blog.entity.SystemLog;
import com.example.blog.entity.User;
import com.example.blog.exception.ResourceNotFoundException;
import com.example.blog.repository.SystemLogRepository;
import com.example.blog.repository.UserRepository;
import com.example.blog.service.SystemLogService;
import jakarta.persistence.criteria.Predicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SystemLogServiceImpl implements SystemLogService {
    @Autowired
    private SystemLogRepository systemLogRepository;

    @Autowired
    private UserRepository userRepository;

    @Override
    @Transactional
    public SystemLogDTO createLog(SystemLogDTO logDTO) {
        SystemLog log = new SystemLog();
        log.setType(logDTO.getType());
        log.setLevel(logDTO.getLevel());
        log.setModule(logDTO.getModule());
        log.setAction(logDTO.getAction());
        log.setDescription(logDTO.getDescription());
        log.setParams(logDTO.getParams());
        log.setIpAddress(logDTO.getIpAddress());
        log.setUserAgent(logDTO.getUserAgent());
        log.setExecutionTime(logDTO.getExecutionTime());
        log.setStackTrace(logDTO.getStackTrace());

        if (logDTO.getUserId() != null) {
            User user = userRepository.findById(logDTO.getUserId())
                    .orElseThrow(() -> new ResourceNotFoundException("User", "id", logDTO.getUserId()));
            log.setUser(user);
        }

        return convertToDTO(systemLogRepository.save(log));
    }

    @Override
    public SystemLogDTO getLogById(Long id) {
        return systemLogRepository.findById(id)
                .map(this::convertToDTO)
                .orElseThrow(() -> new ResourceNotFoundException("SystemLog", "id", id));
    }

    @Override
    public Page<SystemLogDTO> getAllLogs(Map<String, String> filters, Pageable pageable) {
        Specification<SystemLog> spec = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            filters.forEach((key, value) -> {
                if (value != null && !value.isEmpty()) {
                    switch (key) {
                        case "type":
                            predicates.add(cb.equal(root.get("type"), value));
                            break;
                        case "level":
                            predicates.add(cb.equal(root.get("level"), value));
                            break;
                        case "module":
                            predicates.add(cb.equal(root.get("module"), value));
                            break;
                        case "action":
                            predicates.add(cb.like(root.get("action"), "%" + value + "%"));
                            break;
                        case "description":
                            predicates.add(cb.like(root.get("description"), "%" + value + "%"));
                            break;
                        case "ipAddress":
                            predicates.add(cb.equal(root.get("ipAddress"), value));
                            break;
                        case "userId":
                            predicates.add(cb.equal(root.get("user").get("id"), Long.parseLong(value)));
                            break;
                    }
                }
            });

            return cb.and(predicates.toArray(new Predicate[0]));
        };

        return systemLogRepository.findAll(spec, pageable).map(this::convertToDTO);
    }

    @Override
    public Page<SystemLogDTO> getLogsByType(String type, Pageable pageable) {
        return systemLogRepository.findByType(type, pageable)
                .map(this::convertToDTO);
    }

    @Override
    public Page<SystemLogDTO> getLogsByLevel(String level, Pageable pageable) {
        return systemLogRepository.findByLevel(level, pageable)
                .map(this::convertToDTO);
    }

    @Override
    public Page<SystemLogDTO> getLogsByModule(String module, Pageable pageable) {
        return systemLogRepository.findByModule(module, pageable)
                .map(this::convertToDTO);
    }

    @Override
    public Page<SystemLogDTO> getLogsByUser(Long userId, Pageable pageable) {
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new ResourceNotFoundException("User", "id", userId));

        return systemLogRepository.findByUser(user, pageable)
                .map(this::convertToDTO);
    }

    @Override
    public Page<SystemLogDTO> getLogsByDateRange(LocalDateTime start, LocalDateTime end, Pageable pageable) {
        return systemLogRepository.findByCreatedAtBetween(start, end, pageable)
                .map(this::convertToDTO);
    }

    @Override
    @Transactional
    public void cleanupOldLogs(int days) {
        LocalDateTime threshold = LocalDateTime.now().minusDays(days);
        systemLogRepository.deleteByCreatedAtBefore(threshold);
    }

    @Override
    public Map<String, Long> getLogStats() {
        Map<String, Long> stats = new HashMap<>();
        
        // 统计各类型日志数量
        stats.put("totalLogs", systemLogRepository.count());
        stats.put("errorLogs", systemLogRepository.findByLevel("ERROR", Pageable.unpaged()).getTotalElements());
        stats.put("warnLogs", systemLogRepository.findByLevel("WARN", Pageable.unpaged()).getTotalElements());
        stats.put("infoLogs", systemLogRepository.findByLevel("INFO", Pageable.unpaged()).getTotalElements());
        
        // 统计各模块日志数量
        stats.put("userLogs", systemLogRepository.findByModule("USER", Pageable.unpaged()).getTotalElements());
        stats.put("articleLogs", systemLogRepository.findByModule("ARTICLE", Pageable.unpaged()).getTotalElements());
        stats.put("commentLogs", systemLogRepository.findByModule("COMMENT", Pageable.unpaged()).getTotalElements());
        stats.put("systemLogs", systemLogRepository.findByModule("SYSTEM", Pageable.unpaged()).getTotalElements());
        
        // 统计各类型操作数量
        stats.put("loginLogs", systemLogRepository.findByType("LOGIN", Pageable.unpaged()).getTotalElements());
        stats.put("operationLogs", systemLogRepository.findByType("OPERATION", Pageable.unpaged()).getTotalElements());
        stats.put("errorTypeLogs", systemLogRepository.findByType("ERROR", Pageable.unpaged()).getTotalElements());

        return stats;
    }

    private SystemLogDTO convertToDTO(SystemLog log) {
        SystemLogDTO dto = new SystemLogDTO();
        dto.setId(log.getId());
        dto.setType(log.getType());
        dto.setLevel(log.getLevel());
        dto.setModule(log.getModule());
        dto.setAction(log.getAction());
        dto.setDescription(log.getDescription());
        dto.setParams(log.getParams());
        dto.setIpAddress(log.getIpAddress());
        dto.setUserAgent(log.getUserAgent());
        
        if (log.getUser() != null) {
            dto.setUserId(log.getUser().getId());
            dto.setUsername(log.getUser().getUsername());
        }
        
        dto.setExecutionTime(log.getExecutionTime());
        dto.setStackTrace(log.getStackTrace());
        dto.setCreatedAt(log.getCreatedAt());
        
        return dto;
    }
} 